﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BLL
{
    public class SimulationWithResources
    {

        #region 计算给定taskList的所有拓扑排序
        public static int getTasklistIndegree(List<MODEL.risk_task> taskList)
        {
            int sum = 0;
            foreach (MODEL.risk_task task in taskList)
            {
                sum += task.InDegree;
            }
            return sum;
        }
        public static void calTopsort(List<MODEL.risk_task> taskList, List<MODEL.risk_link> linkList, List<MODEL.Sequence> priorityArray, MODEL.Sequence _curSeq)
        {
            List<MODEL.risk_task> callBackList = new List<MODEL.risk_task>();
            for (int i = 0; i < taskList.Count; ++i)
            {
                if (taskList[i].InDegree == 0 && !taskList[i].Finished)
                {
                    callBackList.Add(taskList[i]);
                }
            }
            for (int i = 0; i < callBackList.Count; ++i)
            {
                MODEL.risk_task myTask = callBackList[i];
                MODEL.Sequence curSeq = new MODEL.Sequence(_curSeq);
                curSeq.Array.Add(myTask.Task_id);
                myTask.Finished = true;
                for (int j = 0; j < myTask.OutDegree; ++j)
                {
                    MODEL.risk_task succeedTask = null;
                    foreach (MODEL.risk_task t in taskList)
                    {
                        if (t.Task_id == myTask.SucceedTaskId[j])
                            succeedTask = t;
                    }
                    succeedTask.InDegree--;
                }
                calTopsort(taskList, linkList, priorityArray, curSeq);
                myTask.Finished = false;
                for (int j = 0; j < myTask.OutDegree; ++j)
                {
                    MODEL.risk_task succeedTask = null;
                    foreach (MODEL.risk_task t in taskList)
                    {
                        if (t.Task_id == myTask.SucceedTaskId[j])
                            succeedTask = t;
                    }
                    succeedTask.InDegree++;
                }
            }
            if (getTasklistIndegree(taskList) == 0 && _curSeq.Array.Count == taskList.Count)
            {
                priorityArray.Add(_curSeq);
            }
        }

        public static List<MODEL.Sequence> calPrioritySequence(List<MODEL.risk_task> _taskList, List<MODEL.risk_link> linkList)
        {
            List<MODEL.Sequence> priorityArray = new List<MODEL.Sequence>();
            try
            {
                List<MODEL.risk_task> taskList = new List<MODEL.risk_task>();
                foreach (MODEL.risk_task task in _taskList)
                {
                    taskList.Add(task);
                }
                for (int j = 0; j < taskList.Count; ++j)
                {
                    taskList[j].PreTaskId = new int[taskList.Count];
                    taskList[j].SucceedTaskId = new int[taskList.Count];
                }

                //      cal each in/out degree of the task
                foreach (MODEL.risk_link link in linkList)
                {
                    int outDot = link.Task_pre_id;
                    int inDot = link.Task_suc_id;
                    bool outDone = false;
                    bool inDone = false;
                    foreach (MODEL.risk_task task in taskList)
                    {
                        if (task.Task_id == outDot)
                        {
                            task.SucceedTaskId[task.OutDegree++] = inDot;
                            outDone = true;
                        }
                        if (task.Task_id == inDot)
                        {
                            task.PreTaskId[task.InDegree++] = outDot;
                            inDone = true;
                        }
                        if (outDone && inDone)
                            break;
                    }
                }
                MODEL.Sequence _curSeq = new MODEL.Sequence();
                List<MODEL.risk_task> callBackList = new List<MODEL.risk_task>();
                for (int i = 0; i < taskList.Count; ++i)
                {
                    if (taskList[i].InDegree == 0 && !taskList[i].Finished)
                    {
                        callBackList.Add(taskList[i]);
                    }
                }
                for (int i = 0; i < callBackList.Count; ++i)
                {
                    MODEL.risk_task myTask = callBackList[i];
                    MODEL.Sequence curSeq = new MODEL.Sequence(_curSeq);
                    curSeq.Array.Add(myTask.Task_id);
                    myTask.Finished = true;
                    for (int j = 0; j < myTask.OutDegree; ++j)
                    {
                        MODEL.risk_task succeedTask = null;
                        foreach (MODEL.risk_task t in taskList)
                        {
                            if (t.Task_id == myTask.SucceedTaskId[j])
                                succeedTask = t;
                        }
                        succeedTask.InDegree--;
                    }
                    calTopsort(taskList, linkList, priorityArray, curSeq);
                    myTask.Finished = false;
                    for (int j = 0; j < myTask.OutDegree; ++j)
                    {
                        MODEL.risk_task succeedTask = null;
                        foreach (MODEL.risk_task t in taskList)
                        {
                            if (t.Task_id == myTask.SucceedTaskId[j])
                                succeedTask = t;
                        }
                        succeedTask.InDegree++;
                    }
                }
                for (int i = 0; i < callBackList.Count; ++i)
                {
                    callBackList[i].Finished = true;
                }

                return priorityArray;


            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion

        #region 计算一次仿真的关键路径(带资源)
        /*
         * 任务有优先级，资源没有优先级
         * 没有考虑子节点的并行
         * 返回的是最短的时间
         * status: 0->等待状态 1->就绪状态 -1->完毕状态 
         * 还没写解除死锁
         */
        private static double minTotalMoney = 0;
        private static double minTotoalDuration = 0;
        public static double calSimShortestPath(int projectId, List<MODEL.risk_task> _taskList, List<MODEL.risk_link> _linkList)
        {
            CommonUtils.unionTaskList(_taskList, _linkList);
            List<MODEL.Sequence> priorityArray = calPrioritySequence(_taskList, _linkList);
            double totalMoney = 0;
            double totoalDuration = 0;

            foreach (MODEL.Sequence seq in priorityArray)
            {
                //保存项目资源信息
                List<MODEL.risk_project_res_assignment> prjResAssignList = CommonArugment.getPrjResAssign.getPrjResAssignListByPrjId(projectId);

                bool canWork = true;
                int[] pArray = seq.Array.ToArray();
                List<MODEL.risk_task> taskList = new List<MODEL.risk_task>();
                foreach (MODEL.risk_task task in _taskList)
                {
                    taskList.Add(task);
                }

                //寻找入度为0的点
                bool flag = true;
                List<MODEL.risk_task> taskReadyQueue = new List<MODEL.risk_task>();
                while (flag && canWork)
                {
                    flag = false;
                    List<MODEL.risk_task> callBackList = new List<MODEL.risk_task>();
                    for (int i = 0; i < taskList.Count; ++i)
                    {
                        if (taskList[i].InDegree == 0 && taskList[i].Status == 0)
                        {
                            callBackList.Add(taskList[i]);
                            flag = true;
                        }
                    }
                    for (int i = 0; i < pArray.Length; ++i) //按照顺序分配资源
                    {
                        for (int j = 0; j < callBackList.Count; ++j)
                        {
                            if (callBackList[j].Task_id != pArray[i])
                                continue;
                            MODEL.risk_task myTask = callBackList[j];
                            //给myTask分配资源，status=1                           
                            if (CommonUtils.allocateResource(projectId, myTask))
                            {
                                myTask.Status = 1;//资源够了，变成就绪态
                                taskReadyQueue.Add(myTask);
                            }
                        }
                    }
                    if (taskReadyQueue.Count > 0)//至少有一个是能run滴
                    {
                        //找到value最小的那个一个
                        double minValue = CommonMsg.maxNumber;
                        foreach (MODEL.risk_task task in taskReadyQueue)
                        {
                            if (task.Value < minValue)
                                minValue = task.Value;
                        }
                        totoalDuration += minValue;
                        for (int i = 0; i < taskReadyQueue.Count; ++i)
                        {
                            //???这里钱算的不对
                            totalMoney += CommonUtils.getMoney(taskReadyQueue[i]);
                            if (taskReadyQueue[i].Value <= minValue)//能执行完的执行
                            {
                                CommonUtils.recycleResource(projectId, taskReadyQueue[i]);
                                taskReadyQueue[i].Status = -1;
                                for (int j = 0; j < taskReadyQueue[i].OutDegree; ++j)
                                {
                                    MODEL.risk_task succeedTask = null;
                                    foreach (MODEL.risk_task t in taskList)
                                    {
                                        if (t.Task_id == taskReadyQueue[i].SucceedTaskId[j])
                                            succeedTask = t;
                                    }
                                    if (succeedTask.Status == 0)
                                    {
                                        succeedTask.CalInDegree--;
                                    }
                                }
                                taskReadyQueue.RemoveAt(i--);
                            }
                            else //执行一部分
                            {
                                taskReadyQueue[i].Value -= minValue;
                            }
                        }
                    }
                    else
                    {
                        canWork = false;
                    }
                }

                //还原项目资源信息
                foreach (MODEL.risk_project_res_assignment prjResAssign in prjResAssignList)
                {
                    CommonArugment.getPrjResAssign.updateByPrjIdResId(prjResAssign);
                }
            }
            return -1;
        }
        #endregion


    }
}
